package com.tplhk.retry.service.impl;

import com.tplhk.retry.service.SendService;
import com.tplhk.retry.vo.MessageBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.support.RetryTemplate;

import java.util.Objects;

/**
 * @ClassName : SendServiceImpl
 * @Description : TODO
 * @Author : jqxu
 * @Date: 2023/2/13 10:01
 **/
@Slf4j
public abstract class AbstractSendService implements SendService {

    /**
     * 最大重试次数
     */
    private int maxAttempts = 3;

    /**
     * 初始延迟时间（单位毫秒）
     */
    private long initialInterval = 1000L;
    /**
     * 下次延迟时间是上次延迟的倍数
     */
    private double multiplier = 2D;

    /**
     * 最大延迟时间（单位毫秒）
     */
    private long maxInterval = 5000L;


    @Override
    public Object send(MessageBean messageBean){
        final RetryTemplate template = RetryTemplate.builder().maxAttempts(maxAttempts)
                .retryOn(RuntimeException.class)
                .exponentialBackoff(initialInterval, multiplier, maxInterval)
                .build();

        Object result;

        try {
            result = template.execute((RetryCallback<Object, Throwable>) retryContext -> {
                if (retryContext.getRetryCount() > 1) {
                    log.warn("The Msg[{}] is send for the {} times. The Last failure was caused by {}.",
                            messageBean.key(), retryContext.getRetryCount(), retryContext.getLastThrowable().getMessage());
                }

                // todo handle MSG Server error
                final Object message = AbstractSendService.this.doSend(messageBean);
                if (Objects.isNull(message)) {
                    throw new RuntimeException("Failed to send MSG[" + messageBean.key() + "]!");
                }

                return message;
            }, retryContext -> {
                log.info("完蛋了，重试都失败了");
                log.error("Failed to send MSG[{}] after {} retries!", messageBean.key(), retryContext.getRetryCount());
                return null;
            });
        } catch (Throwable e) {
            throw new RuntimeException(String.format("Failed to send MSG[%s], Caused by %s!", messageBean.key(), e.getMessage()), e);
        }

        return result;

    }


    /**
     * 执行发送消息
     *
     * @param messageBean 消息内容
     * @return 消息模型
     */
    public abstract Object doSend(MessageBean messageBean) throws Exception;


}
